package com.xing.asm.simple;//package com.xing.asm;

import org.objectweb.asm.*;
import org.objectweb.asm.commons.AdviceAdapter;

import java.io.FileOutputStream;
import java.io.IOException;

public class TryCatchBlock extends ClassLoader implements Opcodes {

	public static class Foo {

		public static void execute() {
			System.out.println("-----------");
		}

		public static void changeMethodContent() {
			System.out.println("---------");
		}
	}

	public static class XXX{
		private Foo foo;

		void getEx(Foo foo){
			 foo.execute();
		}
	}

	public static void main(String[] args) throws IOException, IllegalArgumentException, SecurityException {

		ClassReader cr = new ClassReader(Foo.class.getName());
		ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
		ClassVisitor cv = new MethodChangeClassAdapter(cw);
		cr.accept(cv, Opcodes.ASM5);

		byte[] code = cw.toByteArray();


		new XXX().getEx(new Foo());

		FileOutputStream fos = new FileOutputStream("E:\\ljx\\TryCatch.class");
		fos.write(code);
		fos.close();
	}

	static class MethodChangeClassAdapter extends ClassVisitor implements Opcodes {

		public MethodChangeClassAdapter(final ClassVisitor cv) {
			super(Opcodes.ASM4, cv);
		}

		@Override
		public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
			MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);

			mv = new AdviceAdapter(Opcodes.ASM5, mv, access, name, desc) {
				@Override
				protected void onMethodEnter() {
					Label startCatch = newLabel();
					Label endCatch = newLabel();

					visitLabel(startCatch);

					visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");

					visitLdcInsn("this is add method print!");

					visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");

					goTo(endCatch);

					Label handler = new Label();
					visitLabel(handler);

					final int throwableLocal = newLocal(Type.getType(Throwable.class));
					storeLocal(throwableLocal);

					Runnable throwableMessage = new Runnable() {
						public void run() {
							loadLocal(throwableLocal);
						}
					};


//					ProxyUtils.getLogger(this).debug("{}.{}{} threw an exception: {}",throwableMessage);

//					ProxyUtils.loadLogger(this);

//					getStatic(Type.getType(Level.class), Level.FINEST.getName(), Type.getType(Level.class));
//
//					loadLocal(throwableLocal);
//					push("Exception stack:");
//
//					((Logger)ProxyUtils.getLoggerBuilder(this, false).build()).debug((Exception)null, null);

//					visitInsn(177);


//					visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Exception"});
//					visitVarInsn(Opcodes.ASTORE, 1);
//
//					visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
//					visitLdcInsn("1");
//					visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

//					pop();

					visitLabel(endCatch);

					visitTryCatchBlock(startCatch, endCatch, handler, Type.getType(Throwable.class).getInternalName());

				}

				@Override
				protected void onMethodExit(int opcode) {
					super.onMethodExit(opcode);
				}
			};

			return mv;
		}


	}
}
